
#include "../iface/debug.h"
#include "ForwardServer.h"

// I'm going to have to have a session keep-alive function, just in case!

#define FORWARD_BLOCK_SIZE 32768

void *ForwardServer::ClientHandler(apr_thread_t *tthread, void *args)
{
   apr_status_t status;
   ForwardServer *kthis = *((ForwardServer **)(((void **)(args))[0]));
   int i = *((int *)(((void **)(args))[1]));
   apr_pool_t *upperpool, *mp;
   upperpool = apr_thread_pool_get(tthread);
   status = apr_pool_create(&mp, upperpool);
   CheckAPRError(status);

   while (!(kthis->sessionstop))
   {
      kthis->pipearray[i].sessionstart->wait();
      if (kthis->sessionstop) break;
      if (kthis->fchannel)
      {
         kthis->pipearray[i].waiting->lock();
         char *buffer = (char *)malloc(sizeof(char)*FORWARD_BLOCK_SIZE);
         int err = 0;
         while ((!(kthis->pipearray[i].handler_to_send->isClosed())) && 
                (!(kthis->pipearray[i].recv_to_handler->isClosed())) && (!err))
         {
            apr_size_t dataquant = kthis->pipearray[i].recv_to_handler->popFromStream(buffer, FORWARD_BLOCK_SIZE);
            int written_to_fchan = 0;
            int ierr;
            ierr = 1;
            while ((ierr > 0) && (written_to_fchan < dataquant))
            {
               // is this right?
               ierr = libssh2_channel_write(kthis->fchannel, buffer, dataquant);
               if (ierr < 0)
               {
                  errprint("could not write to channel (%d)", ierr);
                  err |= ierr;
                  break;
               }
               written_to_fchan += ierr;
            }
            int read_from_fchan = libssh2_channel_read(kthis->fchannel, buffer, FORWARD_BLOCK_SIZE);
            if (read_from_fchan == LIBSSH2_ERROR_EAGAIN) continue;
            if (read_from_fchan < 0)
            {
               errprint("could not read from channel (%d)", read_from_fchan);
               err |= ierr;
               continue;
            }
            apr_size_t dataquant2 = kthis->pipearray[i].handler_to_send->writeToStream(buffer, read_from_fchan);
         }
         kthis->pipearray[i].waiting->unlock();
         apr_atomic_inc32(&(kthis->pipearray[i].stage));
         kthis->pipearray[i].recv_to_handler->writeEOS();
         apr_atomic_set32(&(kthis->pipearray[i].stage), SERVERSTAGE_SENDING);
         kthis->pipearray[i].handler_to_send->writeEOS();
         free(buffer);
      }
   }
   kthis->pipearray[i].sessionstart->unlock();
   apr_pool_clear(mp);
   apr_pool_destroy(mp);
   ERR_remove_state(0);
   apr_thread_exit(tthread, APR_SUCCESS);
   return NULL;
}

void ForwardServer::SetForwardingChannel(LIBSSH2_CHANNEL *ifchannel)
{
   fchannel = ifchannel;
}
